package com.a0soft.gphone.aTruffleHog.di;

/*
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 3, or (at your option) any
 * later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * Copyright(C) 2011 
 *   Sam Lu <ysl.sam.lu (at) gmail.com>
 *
 */

import java.util.ArrayList;
import java.util.Iterator;

import android.os.Build;

import com.a0soft.gphone.aTruffleHog.util.MiscUtil;

/*
 * /proc/cpuinfo
 * /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
 * /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq
 * /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq
 */
class CpuInfo extends BaseInfo {

    // private static final String LOG_TAG = CpuInfo.class.getSimpleName();

    static void 
    Build(DeviceInfo di)
    {
        di.Put(DeviceInfoKey.K.CP_ABI, Build.CPU_ABI);
        PutSysPropStr(di, DeviceInfoKey.K.CP_ABI2, "CPU_ABI2",
                      "ro.product.cpu.abi2"); // API 8

        StringBuilder sb = new StringBuilder(1024);
        long lSize;

        int nCPUNum = 1;
        sb.setLength(0);
        lSize = MiscUtil.ReadProcOuput("/proc/cpuinfo", sb);
        if (lSize > 0) {
            ArrayList<String> list = _BuildKeyValuePairs(sb.toString());
            di.Put(DeviceInfoKey.K.CP_MIPS, _GetMIPS(list));
            di.Put(DeviceInfoKey.K.CP_FEATURES, _GetFeatures(list));
            nCPUNum = _GetCoreNum(list);
            di.Put(DeviceInfoKey.K.CP_CORE_NUM, nCPUNum);

            Runtime runtime = Runtime.getRuntime();
            di.Put(DeviceInfoKey.K.CP_VM_CORE_NUM,
                   runtime.availableProcessors());

            di.Put(DeviceInfoKey.K.CP_LABEL, _Find(list, "Processor"));
            di.Put(DeviceInfoKey.K.CP_IMPLEMENTER, 
                   _Find(list, "CPU implementer"));
            di.Put(DeviceInfoKey.K.CP_ARCHITECTURE, 
                   _Find(list, "CPU architecture"));
            di.Put(DeviceInfoKey.K.CP_VARIANT, _Find(list, "CPU variant"));
            di.Put(DeviceInfoKey.K.CP_PART, _Find(list, "CPU part"));
            di.Put(DeviceInfoKey.K.CP_REVISION, _Find(list, "CPU revision"));
        }
        
        ArrayList<String> lMinFreqs = new ArrayList<String>(nCPUNum);
        ArrayList<String> lMaxFreqs = new ArrayList<String>(nCPUNum);
        for (int i = 0; i < nCPUNum; i++) {
            sb.setLength(0);
            lSize = MiscUtil.ReadProcOuput(
               String.format("/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_min_freq", i),
               sb);
            lMinFreqs.add(lSize > 0 ? sb.toString().trim() : "0");

            sb.setLength(0);
            lSize = MiscUtil.ReadProcOuput(
               String.format("/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", i),
               sb);
            lMaxFreqs.add(lSize > 0 ? sb.toString().trim() : "0");
            
        }
        di.Put(DeviceInfoKey.K.CP_MIN_FREQ, lMinFreqs);
        di.Put(DeviceInfoKey.K.CP_MAX_FREQ, lMaxFreqs);
    }

    private static String 
    _Find(ArrayList<String> list, String strFind)
    {
        Iterator<String> iter = list.iterator();
        while (iter.hasNext()) {
            String strKey = iter.next();
            String strVal = iter.next();
            if (strFind.equals(strKey)) {
                return strVal;
            }
        }
        return null;
    }

    private static ArrayList<Float> 
    _GetMIPS(ArrayList<String> list)
    {
        ArrayList<Float> strMIPSs = new ArrayList<Float>(4);

        Iterator<String> iter = list.iterator();
        while (iter.hasNext()) {
            String strKey = iter.next();
            String strVal = iter.next();
            if (strKey.equals("BogoMIPS")) {
                float f;
                try {
                    f = Float.parseFloat(strVal);
                }
                catch (NumberFormatException e) {
                    f = 0;
                }
                strMIPSs.add(f);
            }
        }

        return strMIPSs;
    }

    private static int 
    _GetCoreNum(ArrayList<String> list)
    {
        int nCore = 0;

        Iterator<String> iter = list.iterator();
        while (iter.hasNext()) {
            String strKey = iter.next();
            @SuppressWarnings("unused")
            String strVal = iter.next();
            if (strKey.equals("processor"))
                nCore++;
        }

        if (nCore == 0)
            return 1;
        return nCore;
    }

    private static ArrayList<String> 
    _GetFeatures(ArrayList<String> list)
    {
        ArrayList<String> strFeatures = new ArrayList<String>(16);

        Iterator<String> iter = list.iterator();
        while (iter.hasNext()) {
            String strKey = iter.next();
            String strVal = iter.next();
            if (strKey.equals("Features")) {
                String[] strVals = strVal.split(" ");
                for (String strFeature : strVals) {
                    strFeature = strFeature.trim();
                    if (strFeature.length() > 0)
                        strFeatures.add(strFeature);
                }
                break;
            }
        }

        return strFeatures;
    }

    private static ArrayList<String> 
    _BuildKeyValuePairs(String str)
    {
        ArrayList<String> list = new ArrayList<String>(128);

        // aDebug.d(LOG_TAG, "=============");
        // aDebug.d(LOG_TAG, str);
        // aDebug.d(LOG_TAG, "=============");
        String[] strLines = str.split("[\r\n]");
        for (String strLine : strLines) {
            strLine = strLine.trim();
            if (strLine.length() == 0)
                continue;
            String[] strParts = strLine.split(":");
            if (strParts.length != 2)
                continue;
            list.add(strParts[0].trim());
            list.add(strParts[1].trim());
        }

        return list;
    }
}
